package com.contentteam.util.config;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.contentteam.util.config.guice.GetterInterface;
import com.contentteam.util.config.metadata.Getter;
import com.contentteam.util.config.metadata.MethodUtils;
import com.google.inject.AbstractModule;

public abstract class GetterInterfaceBindingGuiceAbstractModul<T> extends
		AbstractModule {

	private GetterInterface properties;

	private static final Log LOG = new Log();

	public GetterInterfaceBindingGuiceAbstractModul(
			final GetterInterface properties) {
		if (properties == null)
			throw new IllegalArgumentException(
					"Passed parameter {properties} is NULL.");

		this.properties = properties;
	}

	@Override
	protected final void configure() {
		bindGetters();

		setupBindings();
	}

	protected abstract void setupBindings();

	protected void bindGetters() {
		final List<Method> getterList = this.properties.getterMethods();

		final Map<String, Getter> getters = collectGetterMethods(getterList);

		for (final Getter method : getters.values()) {
			method.invoke();
		}

	}

	private Map<String, Getter> collectGetterMethods(
			final List<Method> getterList) {
		final Map<String, Getter> rval = new HashMap<String, Getter>(getterList
				.size());

		for (final Method method : getterList) {
			if (!Getter.isAcceptableMethod(method))
				continue;

			final Getter getterDelegate = Getter.createInstance(method, this);

			rval.put(method.getName(), getterDelegate);
		}

		return rval;
	}




	@SuppressWarnings("unchecked")
	public void bindGetter(final Method getterMethod,
			final Class bindType, final Class<? extends Annotation> annotatedWith, final Object getterReturnValue) {

		if (getterReturnValue == null) {
			final String logMsg = LOG.couldntBindObjectProperty(this.getClass(), getterMethod, getterReturnValue);

			throw new NullPointerException(logMsg);
		}

		
		bind(bindType).annotatedWith( annotatedWith ).toInstance( getterReturnValue );
		
	}

	private static final class Log {
		private final static org.apache.log4j.Logger LOGGER = Logger
				.getLogger(GetterInterfaceBindingGuiceAbstractModul.class);

		public String couldntBindObjectProperty(
				@SuppressWarnings( "unchecked" ) final Class<? extends GetterInterfaceBindingGuiceAbstractModul> modulType,
				final Method method,
				final Object value) {

			final String logMsg = "Couldn't bind a module-property [method = "
					+ MethodUtils.simplePrintMethodHeader(method)
					+ "] in this modul [class= " + modulType.getName()
					+ "] as an instance [= " + String.valueOf(value) + "]";

			LOGGER.error( logMsg );
			
			return logMsg;
		}

	}

}
